package conf2;

import conf2.iface.IGamePieceListener;
import conf2.model.EActor;
import conf2.model.ETerritory;
import conf2.model.WorldState;
import conf2.ui.GamePiece;
import conf2.ui.PieceCollection;
import conf2.ui.PlacementPanel;
import conf2.ui.RegionBounds;
import conf2.util.Arr;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.KeyEvent;
import java.util.Collection;
import java.util.EnumMap;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;

class PlacementHandler implements IGamePieceListener, PlacementPanel.Listener {

    private Map<EActor, Point> unplacedPositions = new EnumMap<EActor, Point>(EActor.class);
    private final ETerritory[] validTerritories;
    private final PlacementPanel panel;
    private List<Listener> listeners = new LinkedList<Listener>();
    private final Rectangle unplacedRect;
    private final WorldState ws = new WorldState();
    private final Set<EActor> unplacedActors = new HashSet<EActor>();
    private final PieceCollection pieceColl;

    void addListener(Listener l) {
        listeners.add(l);
    }

    static interface Listener {

        void placementComplete(Map<ETerritory, List<EActor>> placement);
    }

    public PlacementHandler(PlacementPanel panel, Rectangle unplacedRect, Collection<GamePiece> pieces, ETerritory[] validTerritories, Map<EActor, Point> unplacedPositions) {
        this.panel = panel;
        this.unplacedRect = unplacedRect;
        this.unplacedPositions = unplacedPositions;
        this.validTerritories = validTerritories;
        panel.addListener(this);
        pieceColl = new PieceCollection(pieces);
        for (GamePiece gp : pieces) {
            unplacedActors.add(gp.getActor());
        }
    }

    private boolean isPlacementOK() {
        for (ETerritory et : validTerritories) {
            if (et == ETerritory.MORDOR || et == ETerritory.SHIRE) {
                if (!ws.isFull(et)) {
                    return false;
                }
            } else if (ws.getOccupantCount(et) != 1) {
                return false;
            }
        }
        return true;
    }

    public void pieceDropped(GamePiece source, Point where) {
        ETerritory et = RegionBounds.TerritoryIdAt(where);
        EActor ea = source.getActor();
        if (et == null) {
            if (unplacedRect.contains(where)) {
                ws.removeActor(ea);
                unplacedActors.add(ea);
                source.setLocation(unplacedPositions.get(ea));
                PiecePositioner.orderAll(pieceColl, ws);
            } else {
                source.snapback();
            }
        } else if (!Arr.contains(et, validTerritories)) {
            source.snapback();
        } else if (et == ETerritory.SHIRE || et == ETerritory.MORDOR) {
            if (!ws.isFull(et)) {
                putPiece(ea, et);
                PiecePositioner.orderAll(pieceColl, ws);
            } else {
                source.snapback();
            }
        } else {
            if (!ws.isFull(et)) {
                putPiece(ea, et);
                PiecePositioner.orderAll(pieceColl, ws);
            } else {
                source.snapback();
            }
        }
        panel.setOKButtonEnabled(isPlacementOK());
        panel.setResetButtonEnabled(unplacedActors.size() < 9);
    }

    public void pieceClicked(GamePiece source, boolean doubleClick, int keyModifiers) {

        int masked = (keyModifiers & (KeyEvent.CTRL_DOWN_MASK | KeyEvent.SHIFT_DOWN_MASK));
        if (masked != 0) {
            placeRandomly();
        }
    }

    public void pieceAltClicked(GamePiece source, boolean doubleClick, int keyModifiers) {
    }

    public void pieceDragged(GamePiece source, Point where) {
        source.getParent().setComponentZOrder(source, 0);
    }

    public void pieceReleased(GamePiece source) {
    }

    public void okClicked() {
        for (Listener l : listeners) {
            l.placementComplete(ws.getPlacementMap());
        }
    }

    public void resetClicked() {
        panel.setResetButtonEnabled(false);
        panel.setOKButtonEnabled(false);
        clearPlacement();
    }

    private void clearPlacement() {
        for (GamePiece gp : pieceColl) {
            EActor ea = gp.getActor();
            if (ws.isAlive(ea)) {
                ws.removeActor(ea);
                unplacedActors.add(ea);
            }
            gp.setLocation(unplacedPositions.get(ea));
        }
    }

    private void putPiece(EActor who, ETerritory where) {
        ws.placeActor(who, where);
        unplacedActors.remove(who);
    }

    private void placeRandomly() {
        clearPlacement();
        
        EActor[] actors = new EActor[9];
        actors = unplacedActors.toArray(actors);
        int max = actors.length;
        for (ETerritory et : validTerritories) {

            if (et == ETerritory.MORDOR || et == ETerritory.SHIRE) {
                for (int i = 0; i < 4; i++) {
                    int rand = (int) (Math.random() * max);
                    EActor toPlace = actors[rand];
                    actors[rand] = actors[max-1];
                    putPiece(toPlace, et);
                    max--;

                }
            } else {
                int rand = (int) (Math.random() * max);
                EActor toPlace = actors[rand];
                actors[rand] = actors[max-1];
                putPiece(toPlace, et);
                max--;
            }
        }

        panel.setOKButtonEnabled(true);
        panel.setResetButtonEnabled(true);
        
        PiecePositioner.orderAll(pieceColl, ws);
    }
}
